<template>
  <table width="100%" border="0" cellspacing="0" cellpadding="0" class="table">
    <thead class="table-thead">
      <tr>
        <th v-if="type" @click="selectAll">
          <input
            v-if="type == 'checkbox'"
            :type="type"
            :name="name"
            :checked="isAllChecked"
          />
        </th>
        <th
          v-for="item in tableHead"
          :key="item.column"
          @click="headClick(item)"
          :class="{
            descending: prop === item.column && order === 'descending',
            ascending: prop === item.column && order === 'ascending',
            isSortable: item.sortable,
          }"
        >
          <div :style="{ width: item.width, maxWidth: item.maxWidth }">
            {{ item.title }}
          </div>
          <span v-if="item.sortable" class="caret-wrapper">
            <i class="sort-caret ascending"></i>
            <i class="sort-caret descending"></i>
          </span>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr
        v-for="(item, index) in rowList"
        :key="item[rowKey]"
        :class="[
          item.rowStatus === 'disabled' ? 'disabled' : 'hover-highlight',
        ]"
        @click="selectItem(index)"
        @dblclick="doubleclick(item)"
      >
        <td v-if="type">
          <input
            :type="type"
            :name="name"
            :value="item[rowValueProp]"
            :checked="item.rowStatus === 'checked'"
            :disabled="item.rowStatus === 'disabled'"
          />
        </td>
        <td v-for="head in tableHead" :key="head.column">
          <div
            :class="{ cell: head.showOverflow }"
            :style="{ width: head.width, maxWidth: head.maxWidth }"
          >
            <slot :name="head.column" :row="item" :index="index">
              <span v-if="head.showOverflow" :title="item[head.column] || '--'">
                {{ item[head.column] || "--" }}
              </span>
              <span v-else>
                {{ item[head.column] || "--" }}
              </span>
            </slot>
          </div>
        </td>
      </tr>
    </tbody>
  </table>
</template>

<script>
export default {
  name: "OprTable",
  props: {
    tableData: {
      type: Array,
      default: () => [],
    },
    // 对象数组，数组元素格式为{ column: 'xx', name: 'xx' }
    tableHead: {
      type: Array,
      default: () => [],
    },
    // 表格类型：radio-单选 checkbox-多选
    type: String,
    // 当type=radio时，name必须传。当同一个页面使用多个该table组件时，name需不同
    name: String,
    // v-for循环时，用作key的字段名称
    rowKey: {
      type: String,
      required: true,
    },
    // 当type为radio和checkbox时必传,表示用哪一个字段作为该行被选中时的值
    rowValueProp: String,
    defaultSort: {
      type: Object,
      default: () => {
        return {
          prop: "",
          order: "",
        };
      },
    },
  },

  data() {
    return {
      rowList: [],
      isAllChecked: false,
      // 单选框选中时的index
      radioIndex: "",
      // 选中的checkbox值
      checkedValue: [],
      column: "",
      prop: "",
      order: "",
    };
  },

  created() {
    if (!this.rowKey) {
      throw new Error(
        "请传入rowKey属性[rowKey: v-for循环时，用于key的字段名称]"
      );
    }
    this.prop = this.defaultSort.prop;
    this.order = this.defaultSort.order;
    if (this.type) {
      if (!this.rowValueProp) {
        throw new Error(
          "请传入rowValueProp属性[rowValueProp: 当type为radio和checkbox时必传,表示用哪一个字段作为该行被选中时的值]"
        );
      }
      if (this.type === "radio" && !this.name) {
        throw new Error(
          "请传入name属性[当type=radio时，name必须传。当同一个页面使用多个该table组件时，name需不同]"
        );
      }
    }
  },

  methods: {
    selectAll() {
      if (this.type === "checkbox") {
        if (this.isAllChecked) {
          this.rowList.forEach((item) => {
            if (item.rowStatus !== "disabled") {
              item.rowStatus = "unchecked";
            }
          });
        } else {
          this.rowList.forEach((item) => {
            if (item.rowStatus !== "disabled") {
              item.rowStatus = "checked";
            }
          });
        }
        this.isAllChecked = !this.isAllChecked;
        this.$emit(
          "row-select",
          this.rowList.filter((item) => item.rowStatus === "checked"),
          this.rowList.filter((item) => item.rowStatus === "unchecked")
        );
      }
    },
    selectItem(index) {
      if (this.type) {
        if (this.rowList[index].rowStatus === "disabled") return;
        if (this.type === "radio") {
          if (index !== this.radioIndex) {
            if (this.radioIndex !== "") {
              this.$set(this.rowList, this.radioIndex, {
                ...this.rowList[this.radioIndex],
                rowStatus: "unchecked",
              });
            }
            this.$set(this.rowList, index, {
              ...this.rowList[index],
              rowStatus: "checked",
            });
            this.radioIndex = index;
            this.$emit("row-select", this.rowList[this.radioIndex]);
          }
        } else if (this.type === "checkbox") {
          const status = this.rowList[index].rowStatus;
          this.$set(this.rowList, index, {
            ...this.rowList[index],
            rowStatus: status === "checked" ? "unchecked" : "checked",
          });
          this.$emit(
            "row-select",
            this.rowList.filter((item) => item.rowStatus === "checked"),
            this.rowList.filter((item) => item.rowStatus === "unchecked")
          );
        }
      }
    },
    headClick(row) {
      if (row.sortable) {
        if (row.column === this.prop) {
          this.order = this.order === "descending" ? "ascending" : "descending";
        } else {
          this.prop = row.column;
          this.order = "descending";
        }
        this.$emit("row-sortChange", {
          prop: row.column,
          order: this.order,
        });
      }
    },
    doubleclick(row) {
      this.$emit("dblclick", row);
    },
  },
  watch: {
    tableData(newVal) {
      this.rowList = [...newVal];
      this.isAllChecked = false;
      this.radioIndex = "";
      this.checkedValue = [];
    },
  },
};
</script>

<style lang="scss" scoped>
.table {
  opacity: 0.94;
  border: 1px solid #e1e6eb;
  border-collapse: collapse;
  .caret-wrapper {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    height: 34px;
    width: 24px;
    vertical-align: middle;
    cursor: pointer;
    overflow: initial;
    position: relative;
  }
  .isSortable {
    cursor: pointer;
  }
  .descending {
    .sort-caret.descending {
      border-top-color: #409eff;
    }
  }
  .ascending {
    .sort-caret.ascending {
      border-bottom-color: #409eff;
    }
  }
  .sort-caret {
    width: 0;
    height: 0;
    border: 5px solid transparent;
    position: absolute;
    left: 7px;
  }
  .sort-caret.ascending {
    border-bottom-color: #c0c4cc;
    top: 5px;
  }
  .sort-caret.descending {
    border-top-color: #c0c4cc;
    bottom: 7px;
  }
  .cell {
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    word-break: break-all;
    line-height: 36px;
    height: 36px;
  }
}

.table-thead {
  background: #f5f6fa;
  font-size: 12px;
  color: #393939;
  height: 36px;
}

td {
  text-align: center;
  font-size: 12px;
  color: #333333;
  &.operate-td {
    text-align: left;
    width: 160px;
    padding-left: 40px;
  }
}

tr {
  height: 36px;
  border-bottom: 1px solid #e1e6eb;

  &.hover-highlight:hover {
    background-color: #f7ffef;
  }

  &.disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
}
</style>
